package com.jediterm.terminal;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * @author traff
 */
public class TerminalColor {
    public static final com.jediterm.terminal.TerminalColor BLACK = index(0);
    public static final com.jediterm.terminal.TerminalColor WHITE = index(15);

    private final int myColorIndex;
    private final Color myColor;
    private final Supplier<Color> myColorSupplier;

    public TerminalColor(int colorIndex) {
        this(colorIndex, null, null);
    }

    public TerminalColor(int r, int g, int b) {
        this(-1, new Color(r, g, b), null);
    }

    public TerminalColor(@NotNull Supplier<Color> colorSupplier) {
        this(-1, null, colorSupplier);
    }

    private TerminalColor(int colorIndex, @Nullable Color color, @Nullable Supplier<Color> colorSupplier) {
        if (colorIndex != -1) {
            assert color == null;
            assert colorSupplier == null;
        } else if (color != null) {
            assert colorSupplier == null;
        } else {
            assert colorSupplier != null;
        }
        myColorIndex = colorIndex;
        myColor = color;
        myColorSupplier = colorSupplier;
    }

    public static @NotNull com.jediterm.terminal.TerminalColor index(int colorIndex) {
        return new com.jediterm.terminal.TerminalColor(colorIndex);
    }

    public static com.jediterm.terminal.TerminalColor rgb(int r, int g, int b) {
        return new com.jediterm.terminal.TerminalColor(r, g, b);
    }

    public boolean isIndexed() {
        return myColorIndex != -1;
    }

    public @NotNull Color toAwtColor() {
        if (isIndexed()) {
            throw new IllegalArgumentException("Color is indexed color so a palette is needed");
        }

        return myColor != null ? myColor : Objects.requireNonNull(myColorSupplier).get();
    }

    public int getColorIndex() {
        return myColorIndex;
    }

    public @NotNull String toHexString16() {
        Color color = toAwtColor();

        // (n * 0x101) converts the 8-bit number to 16 bits.
        String red = padStart(Integer.toHexString(color.getRed() * 0x101), 4, '0');
        String green = padStart(Integer.toHexString(color.getGreen() * 0x101), 4, '0');
        String blue = padStart(Integer.toHexString(color.getBlue() * 0x101), 4, '0');

        return red + "/" + green + "/" + blue;
    }

    @SuppressWarnings("SameParameterValue")
    private @NotNull String padStart(@NotNull String str, int totalLength, char ch) {
        return Character.toString(ch).repeat(Math.max(0, totalLength - str.length())) + str;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        com.jediterm.terminal.TerminalColor that = (com.jediterm.terminal.TerminalColor) o;
        return myColorIndex == that.myColorIndex && Objects.equals(myColor, that.myColor);
    }

    @Override
    public int hashCode() {
        return Objects.hash(myColorIndex, myColor);
    }

    public static @Nullable com.jediterm.terminal.TerminalColor awt(@Nullable Color color) {
        if (color == null) {
            return null;
        }
        return rgb(color.getRed(), color.getGreen(), color.getBlue());
    }
}
